package com.etl.task.basic;

import com.etl.enums.ScheduleStatusEnum;
import com.etl.extract.DatabaseBuilder;
import com.etl.extract.ScheduleTask;
import com.etl.sys.service.ISysScheduleService;
import com.google.common.base.Stopwatch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 任务抽象类
 *
 * @author: chenfenghai
 * @version: 1.0
 * @date: 2020-10-15 9:55
 */
@Slf4j
public abstract class AbstractTask implements ITask {

    @Autowired
    protected DatabaseBuilder databaseBuilder;
    @Autowired
    protected ISysScheduleService sysScheduleService;

    /**
     * 执行任务
     *
     * @param scheduleTask 调度任务
     */
    @Override
    public void execute(ScheduleTask scheduleTask) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        log.debug("Execute schedule starting: {}\n Parameter: {}",
                scheduleTask.getSchedule().getScheduleId(), scheduleTask);
        // 检查调度任务是否可运行
        if (!checkTaskScheduleRunnable(scheduleTask)) {
            return;
        }
        // 更新调度状态为运行中
        sysScheduleService.updateScheduleStatus(
                scheduleTask.getSchedule().getScheduleId(), ScheduleStatusEnum.RUNNING);
        // 处理数量
        int handlerNum = 0;
        // 循环执行任务
        do {
            // 任务结果
            TaskResult taskResult = null;
            try {
                // 执行任务并返回结果
                taskResult = executeTask(scheduleTask);
                if (Objects.nonNull(taskResult) && taskResult.isSuccess()) {
                    // 当执行成功后，更新当前调度任务最后标记
                    scheduleTask.getSchedule().setLastSign(taskResult.getLastSign());
                    handlerNum = taskResult.getHandlerNum();
                }
            } catch (Exception ex) {
                log.error("Execute schedule failed: {}, task schedule: {}",
                        scheduleTask.getSchedule().getScheduleId(), scheduleTask);
                log.error("Execute schedule failed, unknown error: ", ex);
            }
            // 更新调度结果
            sysScheduleService.updateScheduleResult(
                    scheduleTask.getSchedule().getScheduleId(), taskResult);
        } while (handlerNum >= scheduleTask.getSchedule().getLimitNum());
        // 更新调度状态为等待中
        sysScheduleService.updateScheduleStatus(
                scheduleTask.getSchedule().getScheduleId(), ScheduleStatusEnum.WAITING);
        log.debug("Execute schedule completed: {}, Consume Time：{} ms",
                scheduleTask.getSchedule().getScheduleId(),
                stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    /**
     * 验证调度任务参数
     *
     * @param scheduleTask 调度任务
     * @return boolean
     */
    private boolean validTaskSchedule(ScheduleTask scheduleTask) {
        return Objects.isNull(scheduleTask)
                || Objects.isNull(scheduleTask.getSchedule())
                || Objects.isNull(scheduleTask.getTask())
                || Objects.isNull(scheduleTask.getModule())
                || Objects.isNull(scheduleTask.getCinema())
                || Objects.isNull(scheduleTask.getTenant());
    }

    /**
     * 检查调度任务是否可运行
     *
     * @param scheduleTask 调度任务
     * @return boolean
     */
    private boolean checkTaskScheduleRunnable(ScheduleTask scheduleTask) {
        if (validTaskSchedule(scheduleTask)) {
            log.error("Execute schedule failed: {}, parameter error: {}",
                    scheduleTask.getSchedule().getScheduleId(), scheduleTask);
            return false;
        }
        return true;
    }

    /**
     * 执行任务抽象方法
     *
     * @param scheduleTask 调度任务
     * @return TaskResult
     */
    public abstract TaskResult executeTask(ScheduleTask scheduleTask);
}
